/*
 * CMediaFileConvService.cpp
 *
 *  Created on: 2023年7月12日
 *      Author: terry
 */

#include "CMediaFileConvService.h"

CMediaFileConvService::CMediaFileConvService()
    :m_mode(MODE_ON_DEMAND)
    ,m_sink()
{
}

CMediaFileConvService::~CMediaFileConvService()
{
    close();
}

bool CMediaFileConvService::open(int mode, UMediaFileConverterSink* sink)
{
    if (!sink)
    {
        return false;
    }

    m_mode = mode;
    m_sink = sink;

    if (!isRunning())
    {
        start();
    }

    return true;
}

void CMediaFileConvService::close()
{
    stop();

    m_sink = nullptr;
}

bool CMediaFileConvService::isOpen()
{
    return m_sink != nullptr;
}

bool CMediaFileConvService::add(const char* inputPath, const char* outputPath, int64_t id)
{
    if (!inputPath || !outputPath)
    {
        return false;
    }

    ConvTask convTask;
    convTask.inPath = inputPath;
    convTask.outPath = outputPath;
    convTask.id = id;

    {
        std::lock_guard< std::mutex> lock(m_convMutex);
        m_convTasks.push_back(convTask);
    }

    postEvent();

    return true;
}

bool CMediaFileConvService::remove(const char* inputPath)
{
    bool got = false;
    std::lock_guard< std::mutex> lock(m_convMutex);
    for (ConvTaskQueue::iterator it = m_convTasks.begin(); it != m_convTasks.end(); ++it)
    {
        if (it->inPath == inputPath)
        {
            m_convTasks.erase(it);
            got = true;
            break;
        }
    }
    return got;
}

void CMediaFileConvService::removeAll()
{
    std::lock_guard< std::mutex> lock(m_convMutex);
    m_convTasks.clear();
}

size_t CMediaFileConvService::size()
{
    std::lock_guard< std::mutex> lock(m_convMutex);
    return m_convTasks.size();
}

void CMediaFileConvService::onConvert(UMediaFileConverter* converter, int state, int64_t time, double percent)
{
    if (m_sink)
    {
        m_sink->onConvert(converter, state, time, percent);
    }

    if (state == UMEDIA_CONVERTER_END || state == UMEDIA_CONVERTER_ERROR)
    {
        auto handler = [=]()
        {
            onConvEnd(converter);
        };
        post(handler);
    }
}

void CMediaFileConvService::onIdle()
{
    ConvTask task;
    if (checkFetchConvTask(task))
    {
        startConv(task);
    }
    else
    {
        comn::TaskThread::onIdle();
    }
}

bool CMediaFileConvService::fetchConvTask(ConvTask& task)
{
    bool got = false;
    std::lock_guard< std::mutex> lock(m_convMutex);
    if (m_convTasks.size() > 0)
    {
        task = m_convTasks.front();
        m_convTasks.pop_front();
        got = true;
    }
    return got;
}

bool CMediaFileConvService::checkFetchConvTask(ConvTask& task)
{
    if (isConverting())
    {
        return false;
    }

    return fetchConvTask(task);
}

bool CMediaFileConvService::isConverting()
{
    if (!m_converter)
    {
        return false;
    }

    int state = m_converter->getState();
    return !(state == UMEDIA_CONVERTER_END || state == UMEDIA_CONVERTER_ERROR);
}

void CMediaFileConvService::closeConverter()
{
    if (m_converter)
    {
        m_converter->stop();
        m_converter->close();
        m_converter.reset();
    }
}

void CMediaFileConvService::startConv(ConvTask& task)
{
    m_converter.reset(UMediaFileConverterFactory::create(""), UMediaFileConverterFactory::destroy);

    m_converter->setId(task.id);
    m_converter->setSink(this);

    m_converter->open(task.inPath.c_str(), task.outPath.c_str());
    m_converter->start();
}

void CMediaFileConvService::onConvEnd(UMediaFileConverter* converter)
{
    if (m_converter.get() == converter)
    {
        closeConverter();
    }

}
